package ace.module.captcha.core.impl.manager.handler.impl;

import ace.cmp.json.api.JsonService;
import ace.cmp.kaptcha.core.properties.KaptchaProperties;
import ace.cmp.kaptcha.core.service.KaptchaFactory;
import ace.cmp.util.AceCodecUtils;
import ace.module.captcha.api.enums.CaptchaComponentConfigComponentTypeEnum;
import ace.module.captcha.core.impl.dao.entity.CaptchaComponentConfig;
import ace.module.captcha.core.impl.manager.handler.CaptchaImageHandler;
import ace.module.captcha.core.impl.manager.handler.model.dto.CaptchaImageBase64DataResultDto;
import ace.module.captcha.core.impl.manager.handler.model.dto.CaptchaImageStreamResultDto;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import javax.imageio.ImageIO;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @author Caspar
 * @create 2020/11/5 验证码逻辑服务
 */
@Slf4j
@AllArgsConstructor
@Component
public class KaptchaCaptchaImageHandlerImpl implements CaptchaImageHandler {
  private static final String IMAGE_JPEG = "jpeg";
  private final JsonService jsonService;
  private final KaptchaProperties defaultProperties;
  private final KaptchaFactory kaptchaFactory;

  @Override
  public Boolean support(CaptchaComponentConfig config) {
    return config != null
        && CaptchaComponentConfigComponentTypeEnum.KAPTCHA
            .getCode()
            .equals(config.getComponentType());
  }

  @SneakyThrows
  @Override
  public CaptchaImageStreamResultDto createImage(CaptchaComponentConfig config) {
    KaptchaProperties properties = this.resolvePropertiesFromOrDefault(config);

    DefaultKaptcha kaptcha = kaptchaFactory.create(properties);

    String code = kaptcha.createText();

    BufferedImage bufferedImage = kaptcha.createImage(code);

    ByteArrayOutputStream os = new ByteArrayOutputStream();

    ImageIO.write(bufferedImage, IMAGE_JPEG, os);

    return CaptchaImageStreamResultDto.builder().imageOutputStream(os).code(code).build();
  }

  @SneakyThrows
  @Override
  public CaptchaImageBase64DataResultDto createBase64Data(CaptchaComponentConfig config) {
    KaptchaProperties properties = this.resolvePropertiesFromOrDefault(config);

    DefaultKaptcha kaptcha = kaptchaFactory.create(properties);

    String code = kaptcha.createText();

    BufferedImage bufferedImage = kaptcha.createImage(code);

    ByteArrayOutputStream os = new ByteArrayOutputStream();

    ImageIO.write(bufferedImage, IMAGE_JPEG, os);

    String base64Data = "data:image/jpeg;base64," + AceCodecUtils.encodeBase64(os.toByteArray());

    return CaptchaImageBase64DataResultDto.builder().code(code).base64Data(base64Data).build();
  }

  private KaptchaProperties resolvePropertiesFromOrDefault(CaptchaComponentConfig config) {
    try {
      return this.jsonService.toObject(config.getConfig(), KaptchaProperties.class);
    } catch (Exception ex) {
      log.error(String.format("captchaCategoryId:%s,配置解析失败", config.getId()), ex);
    }
    return this.defaultProperties;
  }
}
